package com.aldobucchi.graph.restrictionTree.eval
{
	
	
	import com.aldobucchi.graph.restrictionTree.RTArcNode;
	import com.aldobucchi.graph.restrictionTree.RTFilterNode;
	import com.aldobucchi.graph.restrictionTree.RTNode;
	import com.aldobucchi.graph.restrictionTree.RTUnionNode;
	import com.aldobucchi.graph.restrictionTree.RTVarNode;
	
	
	
	/**
	 * 
	 * Evals a restriction tree over an in-memory array in the classical form [s[p]=o/[o]]
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */	
	public class SimpleRTEvaluator
	{
		
		
		
		private var rootVarNode:RTVarNode;
		
		
		private var valueProvider:Function;
		
		
		public function SimpleRTEvaluator( rootVarNode:RTVarNode )
		{
			this.rootVarNode = rootVarNode;
		}
		
		
		
		
		public function eval( arr:Array, valueProvider:Function = null ):Array 
		{
		
			valueProvider = valueProvider;
		
			var result:Array = [ ];
			
			for each ( var v:* in arr )
				if ( test( v, rootVarNode ) )
					result.push( v );			
		
			return result;
			
		}
		
		
		
		
		public function test( v:*, node:RTNode ):Boolean
		{
			

		
			if ( node is RTVarNode ) 				// a variable node... it passes if all children pass
			{
			
			
				return testChildren( v, node );
			
			
			}
			else if ( node is RTFilterNode )		// execute a filter using native comparison
			{
				
				
				return ( node as RTFilterNode ).filter.testNative( v );		


			}
			else if ( node is RTArcNode )			// try to take the step. we only support non-inverse Arcs in this datamodel
			{
			
				try {
					
					v = v[ ( node as RTArcNode ).arc.label ]; // step

					return testChildren( v, node );
									
				}
				catch ( e:Error ){ }  				// this is allowed to happen. we consider it a fail
				

				return false;
										
			}
			else if ( node is RTUnionNode )
			{
				
				return testChildren( v, node, true );						
			
			}
		
			return true;
			
		}
		
		


		private function testChildren( v:*, node:RTNode, union:Boolean=false ):Boolean
		{
			
			var child:RTNode;
			var children:Array = node.children.toArray( );
			
			for each ( child in children )
			{
			
				if (  test( v, child ) )
				{
					if ( union )
						return true;				
				}
				else
				{
					if ( ! union )
						return false;				
				}
			
			}	
		
//			if ( union )
//				return false;
		
			return true; // intersection. passed all tests
		}




	}
	

}



